package pl.edu.agh.student.janikhankus.tree;

import java.util.ArrayList;
import java.util.ArrayList;
import java.util.List;

import org.antlr.runtime.CommonTokenStream;
import org.antlr.runtime.Token;

/**
 * Class which is responsible for creating grammar hierarchy. 
 * 
 * @author Jaroslaw Janik
 */
public class GrammarTreeCreator {

	/**
	 * Creates grammar hierarchy from tokens passed as parameter. 
	 * Adds as a root of hierarchy temporary production.
	 * 
	 * @param tokensNames Tokens' names.
	 * @param tokens Tokens' stream.
	 * 
	 * @return Grammar hierarchy.
	 */
	public Grammar createGrammarTree(String[] tokensNames, CommonTokenStream tokens) {
		
		Grammar grammar = new Grammar();
		
		int tokenIterator = 0;
		int tokenCount = tokens.size() - 2;
		
		while (isMoreProductions(tokenIterator, tokenCount)) {
			tokenIterator = addProduction(grammar, tokensNames, tokens, tokenIterator);
		}
		
		addStartProduction(grammar);
		
		return grammar;
	}
	
	private boolean isMoreProductions(int tokenIterator, int tokenCount) {
		
		return tokenIterator < tokenCount ? true : false;
	}
	
	private int addProduction(Grammar grammar, String[] tokensNames, CommonTokenStream tokens, int tokenIterator) {
			
		List<Production> productions = new ArrayList<Production>();
		
		Token token = tokens.get(tokenIterator);
		
		NonTerminal left = new NonTerminal(token.getText());
		
		tokenIterator += 2;
		token = tokens.get(tokenIterator);
		
		while (!isEndOfProduction(tokensNames[token.getType()])) {
			ArrayList<Symbol> symbols = new ArrayList<Symbol>();
			
			Production production = new Production();
			production.setLeft(left);
			
			tokenIterator += 2;
			token = tokens.get(tokenIterator);
			
			while (!isEndOfSequence(tokensNames[token.getType()])) {
				Symbol symbol;
			
				token = tokens.get(tokenIterator);
				
				String tokenName = tokensNames[token.getType()];
				
				if (isTerminal(tokenName)) {
					symbol = new Terminal(token.getText());
				} else if (isNonTerminal(tokenName)) {
					symbol = new NonTerminal(token.getText());
				} else {
					symbol = new Epsylon();
				}
				
				symbols.add(symbol);
					
				tokenIterator += 2;
				token = tokens.get(tokenIterator);
			}
			
			production.setRight(symbols);
			productions.add(production);
		}
		
		tokenIterator += 2;
		token = tokens.get(tokenIterator);
		
		for(Production production : productions) {
	
			production.setProbability(Double.parseDouble(token.getText()));
			grammar.addProduction(production);
		}
		
		tokenIterator += 2;
		
		return tokenIterator;
	}
	
	private void addStartProduction(Grammar grammar) {
		
		Production firstProduction = grammar.getProductionList().getFirst();
		Production startProduction = new Production();
		
		startProduction.setLeft(new NonTerminal(firstProduction.getLeft().getName() + '\''));
		
		ArrayList<Symbol> symbols = new ArrayList<Symbol>();
		symbols.add(firstProduction.getLeft());
		
		startProduction.setRight(symbols);
		
		startProduction.setProbability(1.0);
		
		grammar.addStartProduction(startProduction);
	}
	
	private boolean isEndOfSequence(String name) {
		
		return (name.compareTo("OR") == 0 || name.compareTo("COLON") == 0) ? true : false;
	}
		
	private boolean isEndOfProduction(String name) {
		
		return (name.compareTo("COLON") == 0) ? true : false;
	}
	
	private boolean isTerminal(String name) {
		
		return (name.compareTo("TERMINAL") == 0) ? true : false;
	}
	
	private boolean isNonTerminal(String name) {
		
		return (name.compareTo("NONTERMINAL") == 0) ? true : false;
	}
}
